package com.yy.micro.magic.core.strategy;

import com.yy.micro.magic.core.config.Content;
import com.yy.micro.magic.core.context.MagicCubeContext;
import com.yy.micro.magic.core.context.ResourceManager;
import com.yy.micro.magic.core.model.ResultCollector;
import com.yy.micro.magic.core.model.RuleDescriptor;
import com.yy.micro.magic.core.model.RuntimeMetadata;
import com.yy.micro.magic.core.provider.ResourceProviderFactory;
import com.yy.micro.magic.exception.ExceptionCategory;
import com.yy.micro.magic.exception.ExceptionManager;
import com.yy.micro.magic.exception.MapException;
import com.yy.micro.magic.ext.domain.code.CodeMapItem;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

public class RuleStrategyAdapter implements RuleStrategy{

    protected RuntimeMetadata metadata;
    protected MagicCubeContext context;
    protected ResultCollector collector;
    protected ExceptionManager exceptionManager;
    protected ResourceManager resourceManager;
//    protected CodeProviders providers;
    protected ResourceProviderFactory factory;
    protected ReentrantLock lock = new ReentrantLock();

    protected Logger logger = LoggerFactory.getLogger(getClass());
    /*
     * (non-Javadoc)
     */
    @Override
    public void process(RuntimeMetadata metadata, ResultCollector collector) {
        try {
            lock.lock();
            final RuleDescriptor rule = metadata.getRule();
            if (null == rule) {
                String message = String.format(
                        "Strategy=[ %s ] key= [%s ] RuleDescriptor is null", metadata.getStrategy(), metadata.getKey());
                throw MapException.create(message);
            }
            this.metadata = metadata;
            this.collector = collector;
            this.context = metadata.getRequest().getContext();
            this.exceptionManager = collector.getExceptionManager();
            this.resourceManager = this.context.getManager();
//            this.providers = this.resourceManager.getValue(CodeProviders.class,CodeProviders.class.getSimpleName(),CodeProviders.class);
            this.factory = this.context.getFactory();
            process(metadata);
        }catch (Exception e){
            logger.warn(String.format("Strategy[%s] exception [%s]",metadata.getStrategy(),e.getMessage()));
            addException(MapException.create(e));
        } finally{
            lock.unlock();
        }
    }



    protected void process(RuntimeMetadata metadata) {
        addResult(metadata.getRule().getName(), metadata.getInputValue(true));
    }

    /**
     *根据码表名和value查找对应的值，默认值为value
     * @param name  码表名
     * @param value  码值
     * @return
     */
    protected Object findCodeTargetValue(String name,Object value){
        return findCodeTargetValue(name,value,value);
    }

    /**
     * 根据码表名和value查找对应的值，默认值为value
     * @param name 码表名
     * @param value  码值
     * @param defaultValue  传入
     * @return
     */
    protected Object findCodeTargetValue(String name,Object value,Object defaultValue){
        if(null != factory){
            Object obj= factory.findCodeTargetValue(metadata.getPlanCode(),name,value);
            if (null == obj){
                return defaultValue;
            }else {
                return obj;
            }
        }
        return null;
    }

    /**
     * 根据码表名和码值 查到对应的码表映射项。
     * @param name  码表名
     * @param value 码值
     * @return
     */
    protected CodeMapItem findCodeMapItem(String name, Object value){
        if(null != factory){
            return factory.findCodeItem(metadata.getPlanCode(),name,value);
        }
        return null;
    }

    protected void addTempResult(String name,Object value){
        addResult(name,metadata.getInputValue());
        addResult(Content.CACHE_TEMP_RESULT_VALUE.concat(name),value);
    }

    protected void addResult(Object value){
        addResult(metadata.getRule().getName(),value);
    }

    protected void addResult(String name,Object value){
        addResult(name,value,null);
    }

    protected void addResult(String name,Object value,Map<String,Object> result){
        if (null != result){
            result.put(name,value);
        }else{
            result=getTargetResult();
            result.put(name,value);
        }
    }

    protected Map<String,Object> getTargetResult(){
        return collector.getResult(getTargetKey());
    }

    protected String getTargetKey(){
        final RuleDescriptor rule = metadata.getRule();
        String key = metadata.getKey();
        if (null != rule){
            key = rule.getKey();
        }
        return key;
    }

    protected void addException(String message){
        this.addException(message,ExceptionCategory.BUSINESS);
    }

    protected void addException(String message, ExceptionCategory category){
        addException(MapException.create(message, category));
    }

    protected void addException(String message, Throwable throwable){
        addException(MapException.create(message,throwable,ExceptionCategory.RUNTIME));
    }

    protected void addException(MapException e){
        if (null !=exceptionManager){
            exceptionManager.addException(e);
        }else {
            logger.warn(String.format("strategy[%s] exception manager is null !",metadata.getStrategy()));
        }
    }

}
